﻿using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;

namespace Spelprojekt
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class MasterController : Microsoft.Xna.Framework.Game
    {
        //for debugging
        public static bool g_isDebugging = false;
        public static float gravity;

        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;

        float m_elapsedTime = 0;

        float m_timeToLive = 0.10f;

        //Interfaces
        View.IGameView m_gameView = new View.GameView();

        //Views        
        View.GameAssets m_gameAssets = new View.GameAssets();
        View.IntroView m_IntroView = new View.IntroView();        
        View.Input m_input = new View.Input();
        View.Camera m_camera = new View.Camera();
        View.MenuView m_menuView = new View.MenuView();

        //Models
        Model.Menu m_menu = new Model.Menu();
        Model.Game m_game = new Model.Game();
        Model.Player m_player = new Model.Player();
        Model.Enemy m_enemy = new Model.Enemy();

        //Controllers
        Controller.GameStates m_gameState = new Controller.GameStates();

        int m_level;
        int m_lastLevel = 5;

        public MasterController()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
        }

        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {
            // TODO: Add your initialization logic here
            Window.Title = "PsykoGame";
            graphics.PreferredBackBufferWidth = View.Camera.g_width;
            graphics.PreferredBackBufferHeight = View.Camera.g_height;
            graphics.IsFullScreen = false;
            graphics.ApplyChanges();

            this.IsMouseVisible = true;

            m_gameState.State = Controller.GameStates.States.Menu;

            m_level = 1;
            m_game = new Spelprojekt.Model.Game(m_level);

            base.Initialize();
        }

        /// <summary>
        /// LoadContent will be called once per game and is the place to load
        /// all of your content.
        /// </summary>
        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.                                 
            spriteBatch = new SpriteBatch(GraphicsDevice);

            // TODO: use this.Content to load your game content here
            m_gameAssets.LoadResources(Content);
        }

        /// <summary>
        /// UnloadContent will be called once per game and is the place to unload
        /// all content.
        /// </summary>
        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
        }

        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Update(GameTime gameTime)
        {
            // Allows the game to exit
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();

            // TODO: Add your update logic here           

            if (m_gameState.State == Controller.GameStates.States.Game)
            {
                //update game
                m_game.Update((float)gameTime.ElapsedGameTime.TotalSeconds);               

                if (m_game.m_map.IsInHole(m_game.m_player.m_position))
                {
                    m_game.m_player.State = Model.Player.PlayerState.Dead;
                }

                if (m_game.m_map.IsAtExit(m_game.m_player.m_position, m_game.m_player.m_size, Model.Tile.TileType.Exit))
                {
                    if (m_level < m_lastLevel)
                    {
                        m_game.m_player.State = Model.Player.PlayerState.Win;
                    }
                    else if(m_level < m_lastLevel == false)
                    {
                        m_game.m_player.State = Model.Player.PlayerState.Finished;
                    }
                }                               

                if (m_game.m_player.m_isDead == true)
                {
                    m_game.m_player.State = Model.Player.PlayerState.Dead;
                }

                if (m_input.isESCPressed == true)
                {                    
                    m_gameState.State = Controller.GameStates.States.Pause;                   
                }

                if (m_input.isENTERPressed == true)
                {
                    m_gameState.State = Controller.GameStates.States.Game;
                }                

                //if level is cleared
                if (m_game.LevelIsCleared())
                {
                    //LEVEL CLEARED
                    if (m_level < m_lastLevel)
                    {
                        //change level
                        m_level++;

                        //load level
                        m_game = new Spelprojekt.Model.Game(m_level);

                        //view levelintro and reset it's timer
                        m_gameState.State = Controller.GameStates.States.Intro;
                        m_IntroView = new View.IntroView();
                    }
                    //MAX LEVEL CLEARED
                    else
                    {
                        //temp code
                        //should show credits or return you to the menu or something...

                        m_gameState.State = Controller.GameStates.States.Finished;                        
                        
                        //load level 0
                        /*m_level = 1;
                        m_game = new Spelprojekt.Model.Game(m_level);*/                       
                    }
                }
            }

            if (m_gameState.State == Controller.GameStates.States.Menu)
            {                
                if (m_menu.HasClicked())
                {                  
                    if (m_menu.GetButtonCommand(m_input.GetMousePosition()) == "PLAY")
                    {                        
                        Initialize();

                        m_input.isENTERPressed = true;

                        m_gameState.State = Controller.GameStates.States.Intro;                        

                        m_IntroView = new View.IntroView();
                    }

                    if (m_menu.GetButtonCommand(m_input.GetMousePosition()) == "EXIT")
                    {
                        Exit();
                    }
                    
                    else if (m_menu.GetButtonCommand(m_input.GetMousePosition()) == null)
                    {
                        //Nothing Happens!
                    }
                    
                    else
                    {
                        Console.WriteLine("Unknown button command has been called!");
                    }
                }
                
                m_menu.Update((float)gameTime.ElapsedGameTime.TotalSeconds);
            }

            else if (m_gameState.State == Controller.GameStates.States.Intro)
            {
                m_IntroView.Update((float)gameTime.ElapsedGameTime.TotalSeconds);
                
                if (m_IntroView.m_timeToLive <= 0)
                {
                    m_gameState.State = Controller.GameStates.States.Game;
                }
            }

            else if (m_gameState.State == Controller.GameStates.States.Pause)
            {                
                if (m_input.isENTER())
                {
                    m_gameState.State = Controller.GameStates.States.Game;
                }

                if (m_input.isJumping())
                {                 
                    m_gameState.State = Controller.GameStates.States.Menu;                 
                }
            }

            else if (m_gameState.State == Controller.GameStates.States.Finished)
            {                
                if (m_input.isENTER())
                {
                    m_gameState.State = Controller.GameStates.States.Menu;
                }
            }    
        }

        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Draw(GameTime gameTime)
        {
            if (m_gameState.State == Controller.GameStates.States.Game)
            {
                //input   
                if (m_input.isJumping())
                {
                    if (m_game.m_player.m_position.X < 2 || m_game.m_player.m_position.X > 38 || m_game.m_player.m_position.Y < 4)
                    {
                        //Nothing Happens!
                    }
                    else
                    {
                        m_game.DoPlayerJump();
                    }
                }

                if (m_input.moveLeft())
                {
                    m_game.DoMoveLeft();
                }

                if (m_input.moveRight())
                {
                    m_game.DoMoveRight();
                }

                if (m_input.isESC())
                {
                    m_input.isESCPressed = true;                    
                    m_input.isENTERPressed = false;
                }
              
                if (m_input.isENTER())
                {
                    m_input.isENTERPressed = true;
                    m_input.isESCPressed = false;
                }                

                m_gameView.Draw(m_game, spriteBatch, m_gameAssets, m_elapsedTime);
                m_gameView.DrawParticles(m_game, spriteBatch, m_gameAssets, (float)gameTime.ElapsedGameTime.TotalSeconds);
            }

            else if (m_gameState.State == Controller.GameStates.States.Intro)
            {
                GraphicsDevice.Clear(Color.CornflowerBlue);

                m_gameView.Draw(m_game, spriteBatch, m_gameAssets, m_elapsedTime);

                m_IntroView.Draw(m_game.m_map, spriteBatch, m_gameAssets);
            }

            else if (m_gameState.State == Controller.GameStates.States.Pause)
            {                
                m_gameView.Draw(m_game, spriteBatch, m_gameAssets, m_elapsedTime);
                m_gameView.DrawPaused(m_game.m_map, spriteBatch, m_gameAssets);
            }

            if (m_gameState.State == Controller.GameStates.States.Finished)
            {
                GraphicsDevice.Clear(Color.Black);                

                m_gameView.DrawCleared(m_game.m_map, spriteBatch, m_gameAssets);
            }


            if (m_gameState.State == Controller.GameStates.States.Menu)
            {                
                if (m_input.IsMouseLeftDown())
                {
                    m_menu.m_isMouseDown = true;
                }
                else
                {
                    m_menu.m_isMouseDown = false;
                }

                m_menuView.Draw(m_menu, spriteBatch, m_gameAssets);
                m_gameView.DrawLogo(m_game.m_map, spriteBatch, m_gameAssets);
            }

            if (m_game.m_player.State == Model.Player.PlayerState.Win)
            {
                m_gameState.State = Controller.GameStates.States.Pause;

                m_gameView.DrawWin(m_game.m_map, spriteBatch, m_gameAssets);                
            }
            
            if (m_game.m_player.State == Model.Player.PlayerState.Dead)
            {                              
                if (m_game.IsPlayerDead())
                {
                    m_gameView.OnDeath(m_game.m_player.m_position, m_game.m_player.m_speed);

                    m_timeToLive -= (float)gameTime.ElapsedGameTime.TotalSeconds;

                    if (m_timeToLive <= 0)
                    {
                        m_game = new Spelprojekt.Model.Game(m_level);
                    }
                }                
            }
        }
    }
}
